/*-
 *  Authors:
 *      Zhu Yan
 *
 * A HTTP request Implementation
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>

#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

#include "mc.h"
#include "libmod.h"
#include "log.h"
#include "confparser.h"

#define HR_DEFAULT_HOST "127.0.0.1"
#define HR_DEFAULT_POST_SCRIPT "index"

int mod_init(char *);

static char	conf_hr_post_url[CONF_ITEM_LEN + 1] = HR_DEFAULT_HOST;
static int	conf_hr_port = 80;
static int	conf_hr_retry = 0;

static CONF_STR_CONFIG conf_str_array[] = {
	{"post_url",	conf_hr_post_url},
	{0, 0}
};

static CONF_INT_CONFIG conf_int_array[] = {
	{"port", &conf_hr_port},
	{"retry", &conf_hr_retry},
	{0, 0}
};

static ssize_t 
hr_init(void *arg, void **res)
{
	CURL **cpp;
	CURL *curl_handle;

	CSF_UNUSED_ARG(arg);

	
	cpp = (CURL **) res;
	/* init the curl session */
	curl_handle = curl_easy_init();
	*cpp = curl_handle;
	if (curl_handle != NULL)
		return (PIPELINE_SUCCESS);
	else
		return (PIPELINE_FAILED);
}

static void 
hr_deinit(void *arg, void *res)
{
	CURL *curl_handle;

	CSF_UNUSED_ARG(arg);
	CSF_UNUSED_ARG(res);
	
	curl_handle = (CURL *)res;
	
	curl_easy_cleanup(curl_handle);
	return;
}

static size_t
foo(void *ptr, size_t size, size_t nmemb, void *data)
{
	CSF_UNUSED_ARG(ptr);
	CSF_UNUSED_ARG(data);

	return ( size * nmemb);	
}

static ssize_t 
hr_handler(WTI *wtip, CONN_INFO *cip, void *data, void **res)
{
	CURL **cpp;
	CURL *curl_handle;
	MC_DATA *mcdp;
	CURLcode rc;
	long resp_code;
	char buf[1024];
	int i, j;

	CSF_UNUSED_ARG(cip);
	CSF_UNUSED_ARG(wtip);
	
	mcdp = (MC_DATA *)data;
	
	cpp = (CURL **)res;
	curl_handle = *cpp;
	
	snprintf(buf, 1024, "qval=%s", mcdp->value);
	WLOG_INFO("qval=%s", mcdp->value);

	if (curl_handle != NULL) {
		curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
		curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 120);
		curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10);
		curl_easy_setopt(curl_handle, CURLOPT_URL, conf_hr_post_url);
		curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
		curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, buf);
		curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE,
			mcdp->value_len + 5);
		/* send all data to this function  */
		curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, foo);
		/* we pass our 'chunk' struct to the callback function */
		curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, NULL); 
		curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "csfq/1.0");
		
		curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
		curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0);
	}


	for (i = 0, j = 0; i <= conf_hr_retry; i++) {
		rc = curl_easy_perform(curl_handle);
		curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &resp_code);
		if (resp_code == 200) {
			WLOG_INFO("HTTP SENT OK! URL: %s", conf_hr_post_url);
			break;
		} else if (resp_code != 200 && i < conf_hr_retry) {
			j = j + i;
			WLOG_INFO("HTTP FAILED, RETRY %ds! URL: %s", j, conf_hr_post_url);
			
			usleep(j * 1000 * 1000);
		} else {
			WLOG_ERR("HTTP REQUEST FAILED! URL: %s", conf_hr_post_url);
		}
	}
	if (resp_code != 200 && mcdp->delay) {
		(mcdp->delay)--;
		
		WLOG_INFO("DELAYED!");
		return (PIPELINE_REQUEUE);
	} else {
		WLOG_INFO("CONTINUED!");
		return (PIPELINE_CONTINUE);
	}
}

int 
mod_init(char *mod_name)
{
	int r;

	r = load_conf(NULL, mod_name, conf_int_array, conf_str_array);
	if (r != 0)
		WLOG_ERR("load_conf() failed!");

	set_request_init(hr_init);
	set_request_deinit(hr_deinit);
	set_request_handler(hr_handler);

	return (0);
}

